home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / ivd2dvi / auxiliary.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  16KB  |  592 lines

  1. /*
  2.  *  Auxiliary routines for ivd2dvi.  Copyright 1988 by Larry Denenberg.
  3.  *  May be freely distributed as long as this notice is retained.
  4.  */
  5.  
  6.  
  7. #include <stdio.h>
  8. #include "commands.h"
  9. #include "global.h"
  10.  
  11. /*  Procedures and global variables defined in io.c  */
  12. extern unsigned BufSize;
  13. extern unsigned_byte CopyByte(), ReadByte(), FReadByte();
  14. extern long FReadUnsigned(), FReadSigned(), ReadUnsigned(), ReadSigned();
  15. extern long CopyWord();
  16. extern void WriteByte(), CopyNBytes(), SkipNBytes(), FSkipNBytes();
  17. extern void InitIOBuffers(), BufOverflow(), WriteNumber();
  18.  
  19. /*  Global variables defined in ivd2dvi.c  */
  20. extern char *ProgramName;
  21. extern long XInput, XOutput, WInput, WOutput, DeltaH;
  22. extern int State;
  23. extern boolean ExactOutput;
  24.  
  25.  
  26. /*  Global variables defined here  */
  27. int     FilePushLevel;        /* current excess of PUSH over POP    */
  28. int     MaxFilePushLevel;    /* maximum FilePushLevel seen so far    */
  29. char    *TeXFontDirs;        /* directories to search for TFM files    */
  30. int     NTeXFontDirs;        /* number of directories in TeXFontDirs */
  31. FILE    *tfmfp;            /* fp for currently open TFM file    */
  32. font    *CurFont;        /* font from which we're typesetting    */
  33. font    *FirstFont;        /* head of linked list of all fonts    */
  34. long    *AuxStackPointer;    /* first unused spot on the aux stack    */
  35. long    *AuxBeginStack;        /* first usable spot on the aux stack    */
  36. long    *AuxEndStack;        /* first location beyond the aux stack    */
  37.  
  38.  
  39. /*  Procedures defined in this file, in order of definition  */
  40. void Initializations();
  41. void PushWX(), PopXW(), PushDeltaH(), PopDeltaH(), AuxPush();
  42. long AuxPop();
  43. void PushWrite(), PopWrite(), MaxPushLevelOutput();
  44. font *FindFont();
  45. void FontDefine(), NewFont();
  46. long WordMaybeRead();
  47. unsigned_byte ByteMaybeRead();
  48. void CopyFontDefinition(), SkipFontDefinition();
  49. long CharWidth();
  50. void ReadTFMFile();
  51. boolean TFMOpen(), TFMTrialOpen();
  52. void TFMHeaderLoad(), TFMWidthsLoad(), FontMemoryOverflow();
  53. void BadDVIAbort();
  54.  
  55.  
  56.  
  57. /*
  58.  *  Global initializations.  At this point, the command line has been
  59.  *  processed, so we know /BufSize/ and /ProgramName/.  After trivial
  60.  *  initializations, we change /TeXFontDirs/ from a colon-separated list
  61.  *  to a sequence of null-terminated strings by simply changing each
  62.  *  colon to a null and keeping a count in /NTeXFontDirs/.  Finally, we
  63.  *  set up the /AuxStack/ along with its pointer and end;  giving it
  64.  *  four times the size of a small stack since /PushWX/ puts four things
  65.  *  on it at a time.
  66.  */
  67. void
  68. Initializations()
  69. {
  70.   char *pchar;
  71.  
  72.   State = LTYPESETTING;
  73.   CurFont = FirstFont = NULL;
  74.   MaxFilePushLevel = FilePushLevel = 0;
  75.   InitIOBuffers();
  76.  
  77.   TeXFontDirs = getenv("TEXFONTS");
  78.   if (TeXFontDirs == NULL) TeXFontDirs = TFMAREADEFAULT;
  79.   if (*TeXFontDirs == ':') TeXFontDirs++;
  80.   for (NTeXFontDirs = 0, pchar = TeXFontDirs; *pchar; NTeXFontDirs++) {
  81.     while (*pchar && (*pchar != ':')) pchar++;
  82.     if (*pchar == ':') *pchar++ = '\0';
  83.   }
  84.  
  85.   AuxBeginStack = SEQALLOC(4*(BufSize/SMALLBUFDIVISOR), long);
  86.   AuxEndStack = AuxBeginStack + 4*(BufSize/SMALLBUFDIVISOR);
  87.   AuxStackPointer = AuxBeginStack;
  88.   if (AuxBeginStack == NULL) {
  89.     fprintf(stderr, "\n%s fatal error: can't allocate buffers\n",
  90.             ProgramName);
  91.     exit(3);
  92.   }
  93. }
  94.  
  95.  
  96.  
  97. /*
  98.  *  Save the horizontal motion parameters on the aux stack.
  99.  */
  100. void
  101. PushWX()
  102. {
  103.   AuxPush(WInput);
  104.   AuxPush(WOutput);
  105.   AuxPush(XInput);
  106.   AuxPush(XOutput);
  107. }
  108.  
  109.  
  110.  
  111. /*
  112.  *  Restore the horizontal motion parameters from the aux stack.
  113.  */
  114. void
  115. PopXW()
  116. {
  117.   XOutput = AuxPop();
  118.   XInput = AuxPop();
  119.   WOutput = AuxPop();
  120.   WInput = AuxPop();
  121. }
  122.  
  123.  
  124.  
  125. /*
  126.  *  Save /DeltaH/.  We use the same stack as /PushWX/;  only /EndReflect/
  127.  *  has to worry about the necessary stack discipline.
  128.  */
  129. void
  130. PushDeltaH()
  131. {
  132.   AuxPush(DeltaH);
  133. }
  134.  
  135.  
  136.  
  137. /*
  138.  *  Restore /DeltaH/.
  139.  */
  140. void
  141. PopDeltaH()
  142. {
  143.   DeltaH = AuxPop();
  144. }
  145.  
  146.  
  147.  
  148. /*
  149.  *  Push /value/ onto the auxiliary stack.
  150.  */
  151. void
  152. AuxPush(value)
  153. long value;
  154. {
  155.   *AuxStackPointer++ = value;
  156.   if (AuxStackPointer >= AuxEndStack) BufOverflow();
  157. }
  158.  
  159.  
  160.  
  161. /*
  162.  *  Pop a value from the auxiliary stack.  Underflow means that
  163.  *  something is seriously wrong;  even bad input shouldn't do it.
  164.  */
  165. long
  166. AuxPop()
  167. {
  168.   if (--AuxStackPointer < AuxBeginStack) {
  169.     fprintf(stderr, "\n%s internal error: simulation stack underflow\n",
  170.             ProgramName);
  171.     exit(4);
  172.   }
  173.   return *AuxStackPointer;
  174. }
  175.  
  176.  
  177.  
  178. /*
  179.  *  Write a PUSH command to the output DVI file.  All such commands must
  180.  *  be written by this routine so we can keep an accurate count of how
  181.  *  deep we are.  /FilePushLevel/ keeps this count and /MaxFilePushLevel/
  182.  *  keeps track of the deepest we've ever been.  (This routine should be
  183.  *  called WritePush, but then its name would conflict with WritePop.)
  184.  */
  185. void
  186. PushWrite()
  187. {
  188.   WriteByte(PUSH);
  189.   if (++FilePushLevel > MaxFilePushLevel)
  190.     MaxFilePushLevel = FilePushLevel;
  191. }
  192.  
  193.  
  194.  
  195. /*
  196.  *  Write a POP command to the output DVI file.  All such commands must
  197.  *  be written by this routine, so we can keep an accurate count of how
  198.  *  deep we are.  The error here shouldn't occur no matter what garbage
  199.  *  is in the DVI file since this stuff is checked at an even lower
  200.  *  level; see /NestingValidate/ in io.c.
  201.  */
  202. void
  203. PopWrite() {
  204.   WriteByte(POP);
  205.   if (--FilePushLevel < 0) {
  206.     fprintf(stderr, "\n%s internal error: more pops than pushes!\n",
  207.             ProgramName);
  208.     exit(4);
  209.   }
  210. }
  211.  
  212.  
  213.  
  214. /*
  215.  *  Write out the maximum stack depth necessary to process this file.
  216.  *  That number is exactly /MaxFilePushLevel/, as computed by the two
  217.  *  routines immediately preceding.  However, we start by reading the
  218.  *  old value, and use it instead if it's big enough and the -X flag
  219.  *  was used.  Here's the reason:  TeX doesn't always put the correct
  220.  *  value in this field!  If TeX is writing out a POP that immediately 
  221.  *  follows a PUSH, they are both dropped and nothing goes to the DVI
  222.  *  file.  But the variable that's worrying about the maximum stack
  223.  *  depth is not informed of this optimization.  So if TeX tries to
  224.  *  write "PUSH PUSH PUSH POP POP POP" it thinks that the max stack
  225.  *  depth is 3, but in fact nothing is written.  Thus TeX's behavior
  226.  *  is always conservative.  See paragraphs 601, 619, and 629 of 
  227.  *  Volume B of {\it Computers and Typesetting}.
  228.  */
  229. void
  230. MaxPushLevelOutput()
  231. {
  232.   long inputlevel;
  233.  
  234.   inputlevel = ReadUnsigned(2);
  235.   if (ExactOutput && (inputlevel > MaxFilePushLevel))
  236.     WriteNumber(inputlevel, 2);
  237.   else
  238.     WriteNumber((long) MaxFilePushLevel, 2);
  239. }
  240.  
  241.  
  242.  
  243.  
  244. /*
  245.  *  Find the font associated with /fontnumber/ by searching the list.
  246.  *  If it's not there, return NULL and let the caller worry.
  247.  */
  248. font *
  249. FindFont(fontnumber)
  250. long fontnumber;
  251. {
  252.   font *f;
  253.  
  254.   f = FirstFont;
  255.   while ((f != NULL) && (f->number != fontnumber)) f = f->nextfont;
  256.   return f;
  257. }
  258.  
  259.  
  260.  
  261.  
  262. /*
  263.  *  Define a new font as required by a FNT_DEFn command.  If the font is
  264.  *  already known, we must have seen this FNT_DEFn before---skip it if
  265.  *  simulating, otherwise copy it over.  (A given FNT_DEFn command may be
  266.  *  seen any number of times because we must process them whether we're
  267.  *  simulating or typesetting.)  Call /NewFont/ on never-yet-seen fonts.
  268.  */
  269. void
  270. FontDefine(bytes)
  271. unsigned bytes;
  272. {
  273.   long fontnumber;
  274.  
  275.   fontnumber = ReadUnsigned(bytes);
  276.   if (FindFont(fontnumber) == NULL)
  277.     NewFont(fontnumber, bytes);
  278.   else if (State >= SIMULATING)
  279.     SkipFontDefinition();
  280.   else
  281.     CopyFontDefinition(fontnumber, bytes);
  282. }
  283.  
  284.  
  285.  
  286. /*
  287.  *  Process a font for the first time.  If we're not simulating, we must
  288.  *  copy the FNT_DEFn command and parameters into the output file as we
  289.  *  read them.  Allocate the new font object and link it into the list.
  290.  *  Fill in the /number/, /checksum/, /scalefactor/, /area/, and /name/
  291.  *  fields from the arguments (skip the design size; we don't need it).
  292.  *  Set /loaded/ to FALSE to indicate that we haven't read the TFM file.
  293.  *  Only when we need the width of a character in the font---when
  294.  *  /CharWidth/ is called---do we load the TFM file and fill in the rest
  295.  *  of the fields.  That is, we never read the TFM files of fonts that
  296.  *  aren't used in reflected text.
  297.  */
  298. void
  299. NewFont(fontnumber, bytes)
  300. long fontnumber;
  301. unsigned bytes;
  302. {
  303.   font *newfont;
  304.   unsigned areasize, namesize;
  305.   char *p;
  306.  
  307.   if (State < SIMULATING) {
  308.     WriteByte(FNT_DEF1 + bytes - 1);
  309.     WriteNumber(fontnumber, bytes);
  310.   }
  311.   newfont = OBJALLOC(font);
  312.   if (newfont == NULL) FontMemoryOverflow();
  313.   newfont->nextfont = FirstFont;
  314.   FirstFont = newfont;
  315.   newfont->number = fontnumber;
  316.   newfont->checksum = WordMaybeRead();
  317.   newfont->scalefactor = WordMaybeRead();
  318.   WordMaybeRead();
  319.   areasize = ByteMaybeRead();
  320.   namesize = ByteMaybeRead();
  321.   newfont->area = (char *) calloc(areasize+1, sizeof(char));
  322.   if (newfont->area == NULL) FontMemoryOverflow();
  323.   for (p = newfont->area; areasize != 0; areasize--) *p++ = ByteMaybeRead();
  324.   *p = '\0';
  325.   newfont->name = (char *) calloc(namesize+1, sizeof(char));
  326.   if (newfont->name == NULL) FontMemoryOverflow();
  327.   for (p = newfont->name; namesize != 0; namesize--) *p++ = ByteMaybeRead();
  328.   *p = '\0';
  329.   newfont->loaded = FALSE;
  330. }
  331.  
  332.  
  333.  
  334. /*
  335.  *  Either read or copy a word, depending on whether we're simulating.
  336.  *  This routine and the next are useful because the definition of a
  337.  *  font might be seen for the first time during a simulation or
  338.  *  during normal left-to-right typesetting.  Thus /NewFont/ might or
  339.  *  might not want to copy out parameters as they're read.
  340.  */
  341. long
  342. WordMaybeRead()
  343. {
  344.   if (State >= SIMULATING) return ReadSigned(4); else return CopyWord();
  345. }
  346.  
  347.  
  348.  
  349. /*
  350.  *  Either read or copy a byte, depending on whether we're simulating.
  351.  */
  352. unsigned_byte
  353. ByteMaybeRead()
  354. {
  355.   if (State >= SIMULATING) return ReadUnsigned(1); else return CopyByte();
  356. }
  357.  
  358.  
  359.  
  360. /*
  361.  *  Copy a font definition from the input DVI file to the output file.
  362.  */
  363. void
  364. CopyFontDefinition(fontnumber, bytes)
  365. long fontnumber;
  366. unsigned bytes;
  367. {
  368.   WriteByte(FNT_DEF1 + bytes - 1);
  369.   WriteNumber(fontnumber, bytes);
  370.   CopyNBytes(12L);
  371.   CopyNBytes((long) (CopyByte() + CopyByte()));
  372. }
  373.  
  374.  
  375.  
  376. /*
  377.  *  Skip by a font definition.  The FNT_DEFn command and the first
  378.  *  parameter have already been skipped.
  379.  */
  380. void
  381. SkipFontDefinition()
  382. {
  383.   SkipNBytes(12L);
  384.   SkipNBytes((long) (ReadUnsigned(1) + ReadUnsigned(1)));
  385. }
  386.  
  387.  
  388.  
  389.  
  390. /*
  391.  *  Find the width of character /c/ in /CurFont/.  If the TFM file hasn't
  392.  *  been read, read it.  The /widths/ field is NULL in fonts whose TFM
  393.  *  files we couldn't find; we just return 0 as the width of any character
  394.  *  in such a font.  Carefully reduce /c/ modulo 256 if necessary.  If /c/
  395.  *  is now between /bc/ and /ec/, it's a character in the font.  Get its
  396.  *  value from the /charwidths/ table (whose indices run from 0 to
  397.  *  /ec/-/bc/) and use that number to index the /widths/ table.  If /c/
  398.  *  isn't in the font, issue a warning and return 0.
  399.  */
  400. long
  401. CharWidth(c)
  402. long c;
  403. {
  404.   if (CurFont->loaded == FALSE) ReadTFMFile(CurFont);
  405.   if (CurFont->widths == NULL) return 0L;
  406.   if (c < 0) c = 255 - ((-1 - c) % 256);
  407.     else if (c >= 256) c = c % 256;
  408.   if ((c >= CurFont->bc) &&  (c <= CurFont->ec) &&
  409.        (CurFont->charwidths[c - CurFont->bc] != 0))
  410.     return CurFont->widths[CurFont->charwidths[c - CurFont->bc]];
  411.   fprintf(stderr, "\n%s warning: character %d undefined in font %s\n",
  412.           ProgramName, c, CurFont->name);
  413.   return 0L;
  414. }
  415.  
  416.  
  417.  
  418.  
  419. /*
  420.  *  Read in the width information for a font.  This data isn't read until
  421.  *  we actually need it, viz., the first time /CharWidth/ is called with
  422.  *  /f/ in /CurFont/.  If we can't find the TFM file, we set /f->widths/
  423.  *  to NULL as a flag meaning "assume all widths are zero."  In any case,
  424.  *  we mark /f/ as "loaded" so we don't do this again.
  425.  */
  426. void
  427. ReadTFMFile(f)
  428. font *f;
  429. {
  430.   if (TFMOpen(f)) {
  431.     TFMHeaderLoad(f);
  432.     TFMWidthsLoad(f);
  433.     (void) fclose(tfmfp);
  434.   } else
  435.     f->widths = NULL;
  436.   f->loaded = TRUE;
  437. }
  438.  
  439.  
  440.  
  441. /*
  442.  *  Open the TFM file for a font, returning TRUE if we did so and FALSE
  443.  *  otherwise.  If the name of the font starts with a slash, we only
  444.  *  try to open the exact file.  Otherwise we try prepending each of
  445.  *  the possible TFM directories until we get a hit or run out.  Recall
  446.  *  that at this point /TeXFontDirs/ is a null-separated list of names.
  447.  */
  448. boolean
  449. TFMOpen(f)
  450. font *f;
  451. {
  452.   char *pchar;
  453.   int ndir;
  454.  
  455.   if ((*f->area == '/') || ((!*f->area) && (*f->name == '/'))) {
  456.     if (TFMTrialOpen("", f->area, f->name)) return TRUE;
  457.   } else {
  458.     for (pchar = TeXFontDirs, ndir = NTeXFontDirs; ndir > 0; ndir--) {
  459.       if (TFMTrialOpen(pchar, f->area, f->name)) return TRUE;
  460.       while (*pchar++);
  461.     }
  462.   }
  463.   fprintf(stderr, "\n%s warning: Can't find TFM file for font %s; ",
  464.           ProgramName, f->name);
  465.   fprintf(stderr, "assuming zero width\n");
  466.   return FALSE;
  467. }
  468.  
  469.  
  470.  
  471. /*
  472.  *  Try to open a font file.  The "area" is mostly empty for TeX, but
  473.  *  you never can tell.  On success, leave the file descriptor in the
  474.  *  global variable /tfmfp/ and return TRUE, otherwise return FALSE.
  475.  */
  476. boolean
  477. TFMTrialOpen(path,area,name)
  478. char *path, *area, *name;
  479. {
  480.   static char buffer[MAXFILENAMESIZE];
  481.  
  482.   (void) sprintf(buffer, "%s/%s/%s.tfm", path, area, name);
  483.   tfmfp = fopen(buffer, "r");
  484.   if (tfmfp == NULL) return FALSE; else return TRUE;
  485. }
  486.  
  487.  
  488.  
  489. /*
  490.  *  Set up the remaining fields of the font structure.  Get and store
  491.  *  the first and last character codes and the number of distinct widths
  492.  *  in the font.  Allocate the tables /charwidths/ and /widths/.  Check
  493.  *  the checksum, but skip by the rest of the header.  Finally, read the
  494.  *  values into the /charwidths/ table.
  495.  */
  496. void
  497. TFMHeaderLoad(f)
  498. font *f;
  499. {
  500.   int nchars;
  501.   long lh;
  502.   unsigned_byte *pbyte;
  503.  
  504.   FSkipNBytes(tfmfp,2L);
  505.   lh = FReadUnsigned(tfmfp,2);
  506.   f->bc = FReadUnsigned(tfmfp,2);
  507.   f->ec = FReadUnsigned(tfmfp,2);
  508.   nchars = f->ec - f->bc + 1;
  509.   if (nchars < 0) nchars = 0;
  510.   if (nchars > 0) {
  511.     f->charwidths = SEQALLOC(nchars, unsigned_byte);
  512.     if (f->charwidths == NULL) FontMemoryOverflow();
  513.   }
  514.   f->nw = FReadUnsigned(tfmfp,2);
  515.   if (f->nw > 0) {
  516.     f->widths = SEQALLOC(nchars, long);
  517.     if (f->widths == NULL) FontMemoryOverflow();
  518.   }
  519.   FSkipNBytes(tfmfp,14L);
  520.   if (f->checksum != FReadSigned(tfmfp,4))
  521.     fprintf(stderr, "\n%s warning: checksum mismatch on font %s\n",
  522.             ProgramName, f->name);
  523.   FSkipNBytes(tfmfp, 4*lh - 4);
  524.   for (pbyte = f->charwidths; nchars > 0; nchars--) {
  525.     *pbyte++ = FReadByte(tfmfp);
  526.     FSkipNBytes(tfmfp,3L);
  527.   }
  528. }
  529.  
  530.  
  531.  
  532. /*
  533.  *  Read the character widths of a font from the TFM file and convert
  534.  *  to DVI units, a calculation that must be done with extreme care.
  535.  *  Further explanation is punted to section 571 of volume B of the
  536.  *  Encyclop\ae dia TeXnica.  The results go into the /widths/ table.
  537.  */
  538. void
  539. TFMWidthsLoad(f)
  540. font *f;
  541. {
  542.   int nwidths;
  543.   unsigned_byte a,b,c,d;
  544.   long *pwidth,z,alpha,beta;
  545.  
  546.   z = f->scalefactor;
  547.   alpha = 16;
  548.   while (z >= 040000000L) { z = z/2; alpha = alpha+alpha; }
  549.   beta = 256/alpha;
  550.   alpha *= z;
  551.   nwidths = f->nw;
  552.   for (pwidth = f->widths; nwidths > 0; nwidths--) {
  553.     a = FReadByte(tfmfp); b = FReadByte(tfmfp);
  554.     c = FReadByte(tfmfp); d = FReadByte(tfmfp);
  555.     *pwidth = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
  556.     if (a != 0) {
  557.       if (a != 255) {
  558.     fprintf(stderr, "\n%s fatal error: Bad TFM file for font %s\n",
  559.             ProgramName, f->name);
  560.     exit(2);
  561.       } else *pwidth -= alpha;
  562.     }
  563.     pwidth++;
  564.   }
  565. }
  566.  
  567.  
  568.  
  569. /*
  570.  *  Do you need comments for this one?
  571.  */
  572. void
  573. FontMemoryOverflow()
  574. {
  575.   fprintf(stderr, "\n%s: Insufficient memory for font definitions\n",
  576.           ProgramName);
  577.   exit(3);
  578. }
  579.  
  580.  
  581.  
  582. /*
  583.  *  Abort the run due to junk in the input.
  584.  */
  585. void
  586. BadDVIAbort(message)
  587. char *message;
  588. {
  589.   fprintf(stderr, "\n%s: Malformed DVI file (%s)\n", ProgramName, message);
  590.   exit(2);
  591. }
  592.